package bloodfang.gui;

import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.json.JSONException;
import org.json.JSONObject;

import bloodfang.Attacks;
import bloodfang.Cycle;
import bloodfang.CycleAssassination;
import bloodfang.CycleCombat2;
import bloodfang.CycleSubtlety;
import bloodfang.ProcData;
import bloodfang.ProcInfo;
import bloodfang.Procs;
import bloodfang.Race;
import bloodfang.RaidBuff;
import bloodfang.SetBonus;
import bloodfang.Settings;
import bloodfang.Spec;
import bloodfang.StatBlock;
import bloodfang.Stats;
import bloodfang.Talent;
import bloodfang.Weapon;
import bloodfang.WeaponType;
import bloodfang.Stat;
import bloodfang.battlenet.Loader;

public class GUI extends JFrame implements ActionListener {
	
	private static final long serialVersionUID = 1L;

	public static void main(String[] args){
		SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Turn off metal's use of bold fonts
            UIManager.put("swing.boldMetal", Boolean.FALSE);
            		new GUI();
            }
        });
	}
	
	Font smallFont = new Font(Font.SANS_SERIF, Font.PLAIN, 10);
	
	JButton importChar = new JButton("Import");
	
	HashMap<Stat,JTextField> gearStats = new HashMap<Stat,JTextField>();
	
	JComboBox<Race> race = new JComboBox<Race>(Race.values());
	
	JComponent[] mh = new JComponent[]{	
		new JTextField("0.0"),
		new JTextField("0.0"),
		new JComboBox<WeaponType>(WeaponType.values())
	};
	
	JComponent[] oh = new JComponent[]{	
		new JTextField("0.0"),
		new JTextField("0.0"),
		new JComboBox<WeaponType>(WeaponType.values())
	};
	
	String[] weaponLabel = new String[]{"dps","speed","type"};
	
	JTextField talents = new JTextField("......",6);
	
	HashMap<SetBonus,JCheckBox> setBonus = new HashMap<SetBonus,JCheckBox>();
	HashMap<String,JCheckBox> procs = new HashMap<String,JCheckBox>();
	HashMap<String,JSpinner> procsUpgrade = new HashMap<String,JSpinner>();
	
	JComboBox<Spec> spec = new JComboBox<Spec>(Spec.values());
	
	JButton buttonCalc = new JButton("Calc");
	JTextField dps = new JTextField("0.0");
	
	public GUI(){
		this.setLayout(null);
		this.setSize(600, 500);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		
		JPanel dummy = getOurPanel("Gear Stats");
		dummy.setBounds(5, 5, 150, 200);
		importChar.addActionListener(this);
		dummy.add(importChar);
		dummy.add(Box.createGlue());
		for(Stat s : Stat.values()){
			dummy.add(new JLabel(s.name()+":"));
			JTextField statField = new JTextField("0");
			gearStats.put(s, statField);
			dummy.add(statField);
		}
		this.add(dummy);
		
		dummy = getOurPanel("Main Hand");
		dummy.setBounds(155, 5, 150, 80);
		for(int i = 0; i < mh.length; i++){
			dummy.add(new JLabel("mh "+weaponLabel[i]));
			dummy.add(mh[i]);
		}
		this.add(dummy);
		
		dummy = getOurPanel("Off Hand");
		dummy.setBounds(155, 85, 150, 80);
		for(int i = 0; i < oh.length; i++){
			dummy.add(new JLabel("oh "+weaponLabel[i]));
			dummy.add(oh[i]);
		}
		this.add(dummy);
		
		JPanel dummy2 = getOurPanel("Talents",0,4);
		dummy2.setBounds(5, 205, this.getWidth()-10, 180);
		dummy2.add(new JLabel("String:"));
		dummy2.add(talents);
		dummy2.add(Box.createGlue());
		dummy2.add(Box.createGlue());
		for(int row = 0; row < 6; row++){
			dummy2.add(new JLabel("L"+(row+1)*15));
			ButtonGroup group = new ButtonGroup();
			for(int col = 0; col < 3; col++){
				JRadioButton r = new JRadioButton(Talent.get(row, col).name());
				r.setFont(smallFont);
				r.setSelected(false);
				group.add(r);
				dummy2.add(r);
			}
		}
		this.add(dummy2);
		
		dummy = getOurPanel("Set Bonuses");
		dummy.setBounds(5, 385, 200, 90);
		for(SetBonus sb : SetBonus.values()){
			JCheckBox setBox = new JCheckBox();
			setBox.setText(sb.name());
			this.setBonus.put(sb, setBox);
			dummy.add(setBox);
		}
		this.add(dummy);
		
		dummy2 = getOurPanel("Gear Procs");
		dummy2.setBounds(205, 385, 390, 400);
		Procs procs = new Procs();
		for(ProcData proc : procs.getProcData()){
			JCheckBox procBox = new JCheckBox();
			procBox.setText(proc.name);
			procBox.setFont(smallFont);
			SpinnerModel upgradeModel = new SpinnerNumberModel(0, 0, 4, 1);
			JSpinner upgradeBox = new JSpinner(upgradeModel);
			this.procs.put(proc.name, procBox);
			this.procsUpgrade.put(proc.name, upgradeBox);
			dummy2.add(procBox);
			if(proc.behavior.scaling)
				dummy2.add(upgradeBox);
			else
				dummy2.add(Box.createGlue());
		}
		this.add(dummy2);
		
		dummy = getOurPanel("General Settings");
		dummy.setBounds(305, 5, 200, 100);
		dummy.add(new JLabel("Race:"));
		dummy.add(race);
		dummy.add(new JLabel("Spec:"));
		dummy.add(spec);
		
		buttonCalc.addActionListener(this);
		dummy.add(buttonCalc);
		dummy.add(dps);
		this.add(dummy);
		
		//this.pack();
		this.setVisible(true);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == buttonCalc){
			calc();
		} else if (e.getSource() == importChar){
			importChar();
		} else{
			System.err.println("Error: nothing done yet");
		}
	}
	
	private void importChar() {
		JSONObject json = Loader.getCharacter("eu", "blackmoore", "indz");
		if(json == null){
			return;
		}
		try {
			JSONObject stats = json.getJSONObject("stats");
			System.out.println(stats.toString(2));
			for(Stat stat : Stat.values()){
				if(!stats.has(stat.getBattlenetName())) continue;
				gearStats.get(stat).setText(""+stats.getInt(stat.getBattlenetName()));
			}
			((JTextField) mh[0]).setText(""+stats.getDouble("mainHandDps"));
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	private void calc(){
		StatBlock gearStats = new StatBlock();
		for(Stat s : this.gearStats.keySet()){
			int value = Integer.parseInt(this.gearStats.get(s).getText());
			gearStats.setStat(s, value);
		}
		
		Race race = (Race) this.race.getSelectedItem();
		
		Weapon mh = get_weapon_stats(this.mh);
		Weapon oh = get_weapon_stats(this.oh);
		
		String tal = this.talents.getText();
		
		EnumSet<SetBonus> setB = EnumSet.noneOf(SetBonus.class);
		for(SetBonus sb : this.setBonus.keySet()){
			if(this.setBonus.get(sb).isSelected())
				setB.add(sb);
		}
		
		HashSet<ProcInfo> procs = new HashSet<ProcInfo>();
		for(String proc : this.procs.keySet()){
			if(this.procs.get(proc).isSelected()){
				int upgrade = (int) this.procsUpgrade.get(proc).getValue();
				procs.add(new ProcInfo(proc,upgrade));
			}
		}
		Settings settings = new Settings();
		
		Stats stats = new Stats(settings, gearStats, race, mh, oh, tal, new HashSet<String>(), EnumSet.allOf(RaidBuff.class), setB, procs);
		Attacks attacks = new Attacks(stats);
		
		Spec spec = (Spec) this.spec.getSelectedItem();
		Cycle cycle = null;
		if(spec == Spec.ASSASSINATION){
			cycle = new CycleAssassination(stats,attacks);
		}else if(spec == Spec.COMBAT){
			cycle = new CycleCombat2(stats,attacks);
		}else if(spec == Spec.SUBTLETY){
			cycle = new CycleSubtlety(stats,attacks);
		}else{
			System.err.println("Error: Spec not found: " + spec);
		}
		dps.setText(cycle.get_dps()+"");
	}
	
	private Weapon get_weapon_stats(JComponent[] w){
		double mh_dps = Double.parseDouble(((JTextField) this.mh[0]).getText());
		double mh_speed = Double.parseDouble(((JTextField) this.mh[1]).getText());
		WeaponType mh_type = (WeaponType) ((JComboBox<?>) this.mh[2]).getSelectedItem();
		return new Weapon(mh_dps,mh_speed,mh_type);
	}
	
	private JPanel getOurPanel(String title){
		return getOurPanel(title, 0, 2);
	}
	
	private JPanel getOurPanel(String title,int rows, int cols){
		JPanel p = new JPanel();
		p.setLayout(new GridLayout(rows,cols));
		p.setBorder( BorderFactory.createTitledBorder(title));
		return p;
	}
}
